<?php
require_once ('Zend/Form.php');
require_once ('Zend/Validate/Interface.php');

/**
 * @author Kovács Tamás
 * @category Smithy
 * @package Smithy_Form
 */
class Smithy_Form extends Zend_Form
{
    protected $_elementsAllowed = array();


    /**
     * The default decorators for form elements.
     *
     * @var array
     */
    protected static $_elementDecorators = array(
        'ViewHelper',
        'Description',
        array('HtmlTag', array('tag' => 'dd', 'class' => 'element')),
        array('Label', array('tag' => 'dt'))
    );

    /**
     * The default decorators for form buttons.
     *
     * @var array
     */
    protected static $_buttonDecorators = array(
        'ViewHelper',
        'Description',
        array('HtmlTag', array('tag' => 'dd')),
        array('Label', array('tag' => 'dt'))
    );

    /**
     * The default decorators for the form.
     *
     * @var array
     */
    protected static $_formDecorators = array(
        'FormElements',
        'Form'
    );

    /**
     * @see Zend_Form::loadDefaultDecorators()
     */
    public function loadDefaultDecorators() {
        $this->setDecorators(self::$_formDecorators);
    }

    /**
     * Initialize form.
     *
     * @see Zend_Form::init()
     * @return void
     */
    public function init()
    {
        parent::init();

        $this->addElement(
            new Smithy_Form_Element_Token('securityToken')
        );
    }

    /**
     * Sets the default decorators for elements.
     *
     * @param array|Zend_Config $options
     * @param bool $loadNewDecorators Indicated if we should set the given decorators for the elements that already exists. [OPTIONAL]
     * @return void
     */
    public static function setDefaultElementDecorators($options)
    {
        if ($options instanceof Zend_Config) {
            $options = $options->toArray();
        }

        if (!is_array($options)) {
            throw new Exception('Invalid options provided for Smithy_Form::setDefaultElementDecorators()');
        }

        self::$_elementDecorators = $options;
    }

    /**
     * Sets the default decorators for buttons.
     *
     * @param array|Zend_Config $options
     * @return void
     */
    public static function setDefaultButtonDecorators($options)
    {
        if ($options instanceof Zend_Config) {
            $options = $options->toArray();
        }

        if (!is_array($options)) {
            throw new Exception('Invalid options provided for Smithy_Form::setDefaultButtonDecorators()');
        }

        self::$_buttonDecorators = $options;
    }

    /**
     * Sets the default decorators for the form.
     *
     * @param array|Zend_Config $options
     * @return void
     */
    public static function setDefaultFormDecorators($options)
    {
        if ($options instanceof Zend_Config) {
            $options = $options->toArray();
        }

        if (!is_array($options)) {
            throw new Exception('Invalid options provided for Smithy_Form::setDefaultFormDecorators()');
        }

        self::$_formDecorators = $options;
    }

    /**
     * @see Zend_Form::isValid()
     */
    public function isValid($data)
    {
        if (TRUE === $valid = parent::isValid($data)) {
            return $valid;
        }

        foreach ($this->getElements() as $element) {
            if (TRUE === $element->hasErrors()) {
                $this->addErrorMessages(
                   $element->getErrorMessages()
                );
            }
        }

        return $valid;
    }

    /**
     * Removes the elements, that not in the {@link Smithy_Form::$_elementsAllowed} array.
     *
     * @return Smithy_Form
     */
    public function removeElementsNotAllowed()
    {
        if (empty($this->_elementsAllowed)) {
            return $this;
        }

        foreach ($this->getElements() as $element) {
            if (!in_array($element->getName(), $this->_elementsAllowed) && $element->getName() !== 'securityToken') {
                $this->removeElement($element->getName());
            }
        }

        return $this;
    }

}
